import store2 from 'store2'
import isEqual from 'lodash-es/isEqual'

// 接口自带参
export interface RequestParams {
    url: string
    method: string
    params: object
    data?: {
        success: boolean
        data: any[] | null
    }
}

/**
 * 用户 cache 传参
 * 1.namespace string[必传] 命名空间的唯一值，一般是用户id等
 * 2.request object[非必传] 请求参数，获取缓存数据时，会对比接口参数，参数一致时才会返回对应数据
 * 3.callback function[非必传] 是否设置缓存的回调函数（参数是接口返回的数据，如果有callback，则回调函数返回真时才会缓存数据）
 * 4.expires number[非必传] 过期时间，单位为秒，不传默认长期，（一小时：60 * 60）
 */
export type CacheParams =
    | {
          namespace: string
          callback?: Function
          expires?: number
          params?: any
      }
    | boolean

// 缓存到localstorage的数据：CatcheItem[]
export interface CacheItem {
    params: object
    data?: {
        success: boolean
        data: any[] | null
    }
    expires: number
}

// 直接返回三个函数 useCache getStore saveStore
// 直接返回三个函数 useCache 根据参数返回 getCache 或者 setCache
/**
 * 设置Api缓存
 * 调用时机： 当且仅当接口返回成功时调用
 */

/**
 * 获取Api缓存
 * 调用时机：当且接口调用之前，在拦截器中使用，返回缓存的数据 || null
 */

/**
 * 重载函数
 * 函数参数接口请求数据后，返回一个函数：1.setCacheData || 2.getCacheData
 *
 * 1. params 含有 response 时 返回设置Api缓存方法
 * const setCacheData = cacheApi(params)
 * setCacheData(cache)
 *
 * 2. params 不含有 response 时 返回获取Api缓存
 * const getCacheData = cacheApi(params)
 * const response = getCacheData(cache)
 * if (response) return response
 *
 */
export const useCache = (_params: RequestParams) => {
    const { url = '/login', data } = _params
    let params = _params.params
    const method = _params.method.toUpperCase()

    const setCacheData = (setParams: CacheParams) => {
        if (!setParams) {
            return null
        }
        if (typeof setParams === 'boolean') {
            setParams = {
                namespace: 'userId',
                callback: () => true,
                expires: 60 * 60
            }
        }
        const { namespace = 'userId', callback = () => true, expires } = setParams
        params = setParams.params || params

        // 有回调时 根据 callback 决定是否进行缓存
        if (!callback(data)) return null

        const cacheKey = `${method}-${url.replace(/\?.*$/, '')}`
        const list: CacheItem[] = store2.namespace(namespace).get(cacheKey) ?? []
        const newItem = {
            params,
            data,
            expires: Date.now() + (expires ?? 60 * 60) * 1000
        }
        const itemIndex = list.findIndex((o) => isEqual(params, o.params))
        if (itemIndex > -1) {
            list[itemIndex] = newItem
        } else {
            list.push(newItem)
        }
        store2.namespace(namespace).set(cacheKey, list)
        return null
    }

    const getCacheData = (getParams: CacheParams) => {
        if (!getParams) {
            return null
        }
        if (typeof getParams === 'boolean') {
            getParams = {
                namespace: 'userId',
                params
            }
        }
        const { namespace = 'userId' } = getParams
        const _key = `${method}-${url.replace(/\?.*$/, '')}`
        const list: CacheItem[] = store2.namespace(namespace).get(_key) ?? []
        params = getParams.params || getParams

        const itemIndex = list.findIndex((o) => isEqual(params, o.params))
        if (itemIndex > -1) {
            const catcheItem = list[itemIndex]
            if (Date.now() > catcheItem.expires) {
                list.splice(itemIndex, 1)
                return null
            }

            console.groupCollapsed(`%c缓存接口信息: ${_key}`, 'color: green;')
            console.log('%cparams', 'color: purple', params)
            console.log('%clist', 'color: purple', list)
            console.groupEnd()

            return catcheItem.data
        }
        return null
    }

    if ('data' in _params) {
        return setCacheData
    } else {
        return getCacheData
    }
}

export const saveStore = (params: { namespace?: string; key: string; value: any }) => {
    const { namespace = 'default', key, value } = params
    store2.namespace(namespace).set(key, value)
}

export const getStore = (params: { namespace?: string; key: string }) => {
    const { namespace = 'default', key } = params
    return store2.namespace(namespace).get(key)
}

export default useCache
